import pymongo
from django.shortcuts import render, redirect
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View

# 导入bson
from bson import json_util as jsonb

from myapp.models import *
import json
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

# 导入序列化对象
from myapp.myser import *

# 定义地址和端口
host = '127.0.0.1'
port = 6379

# 建立redis连接
r = redis.Redis(host=host, port=port)


# 商品分类接口
class CategoryInfo(APIView):

    def get(self, request):

        # 进行商品查询
        category = Category.objects.filter()

        # 进行序列化操作
        cate_ser = CategorySer(category, many=True)

        # 进行返回
        return Response(cate_ser.data)


# 商品入库接口
class AddGoods(APIView):

    def post(self, request):

        # 接收参数
        name = request.POST.get('name')
        desc = request.POST.get('desc')
        param = request.POST.get('param')
        cid = request.POST.get('cid')
        price = request.POST.get('price')

        # 接收文件
        imgfile = request.FILES.get('img')
        videofile = request.FILES.get('video')

        # 商品排重
        goods = Goods.objects.filter(name=name).first()

        if goods:
            res = {}
            res['code'] = 405
            res['msg'] = '该商品已经存在'
            return Response(res)

        # 商品头图排重
        if imgfile.name not in UPLOAD_ROOT:
            # 演示视频排重
            if videofile.name not in UPLOAD_ROOT:

                # 存储视频
                f = open(os.path.join(UPLOAD_ROOT, '', videofile.name), 'wb')
                for chunk in videofile.chunks():
                    f.write(chunk)
                # 关闭文件流
                f.close()

                # 建立文件流对象
                f = open(os.path.join(UPLOAD_ROOT, '', imgfile.name), 'wb')
                # 写入文件
                for chunk in imgfile.chunks():
                    f.write(chunk)
                # 关闭文件流
                f.close()
                res = {}
                res['code'] = 200
                res['message'] = '商品添加成功'

            # video存在
            # 建立文件流对象
            f = open(os.path.join(UPLOAD_ROOT, '', imgfile.name), 'wb')
            # 写入文件
            for chunk in imgfile.chunks():
                f.write(chunk)
            # 关闭文件流
            f.close()

        # 进行入库
        goods = Goods(name=name, desc=desc, img=imgfile.name, video=videofile.name,
                      param=param, cid=cid, price=price)
        goods.save()

        # 查询商品ID
        goods = Goods.objects.filter(name=name).first()

        res = {}
        res['code'] = 200
        res['gid'] = goods.id

        return Response(res)

    # 修改商品信息

    def options(self, request):
        # 接受参数
        name = request.POST.get('name')
        desc = request.POST.get('desc', None)
        param = request.POST.get('param')
        cid = request.POST.get('cid')
        price = request.POST.get('price')
        gid = request.POST.get('gid')

        # 接收文件
        imgfile = request.FILES.get('img', None)
        videofile = request.FILES.get('video', None)

        # 查询商品
        goods = Goods.objects.get(id=gid)

        # 商品头图排重
        if imgfile.name not in UPLOAD_ROOT:
            # 演示视频排重
            if videofile.name not in UPLOAD_ROOT:

                # 存储视频
                f = open(os.path.join(UPLOAD_ROOT, '', videofile.name), 'wb')
                for chunk in videofile.chunks():
                    f.write(chunk)
                # 关闭文件流
                f.close()

                # 建立文件流对象
                f = open(os.path.join(UPLOAD_ROOT, '', imgfile.name), 'wb')
                # 写入文件
                for chunk in imgfile.chunks():
                    f.write(chunk)
                # 关闭文件流
                f.close()
                res = {}
                res['code'] = 200
                res['message'] = '商品添加成功'

            # video存在
            # 建立文件流对象
            f = open(os.path.join(UPLOAD_ROOT, '', imgfile.name), 'wb')
            # 写入文件
            for chunk in imgfile.chunks():
                f.write(chunk)
            # 关闭文件流
            f.close()

        # 修改商品信息
        goods.name = name
        goods.desc = desc
        goods.param = param
        goods.cid = cid
        goods.price = price
        goods.img = imgfile.name
        goods.video = videofile.name
        goods.save()

        res = {}
        res['msg'] = '修改成功'
        return Response(res)


# 商品列表接口
class GoodsList(APIView):

    def get(self, request):

        # 当前页
        page = int(request.GET.get('page', 1))
        # 一页多少条数据
        size = int(request.GET.get('size', 4))
        # 定义从哪开始切
        data_start = (page-1) * size
        # 定义切到哪
        data_end = page * size

        # 读取数据库
        goods = Goods.objects.all()[data_start:data_end]

        # 查询总数
        count = Goods.objects.count()

        # 进行序列化操作
        goods_ser = GoodsSer(goods, many=True)

        # 返回
        res = {}
        res['total'] = count
        res['data'] = goods_ser.data
        return Response(res)


# 商品详情接口
class GoodsInfo(APIView):
    def get(self, request):
        # 接收参数
        gid = request.GET.get('gid')
        # 查找商品
        goods = Goods.objects.filter(id=gid).first()
        # 序列化操作
        goods_ser = GoodsSer(goods)
        res = {}
        res['data'] = goods_ser.data
        return Response(res)


# 建立mongo链接对象
mongo_client = pymongo.MongoClient('localhost', 27017)


# 商品标签添加接口
class InsertTags(APIView):
    def get(self, request):

        # 接收参数
        gid = request.GET.get('gid', None)
        tags = request.GET.get('tags', None)
        # 字符串转列表
        tags = tags.split(',')
        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 排重操作
        res = table.find({'gid': str(gid)}).count()
        if res > 0:
            return Response({'msg': '数据重复'})
        else:
            # 入库
            table.insert({'gid': str(gid), 'tags': tags})
            return Response({'msg': '入库成功'})

    def options(self, request):
        # 获取gid
        gid = request.data.get('gid')
        tags = request.data.get('tags')
        # 字符串转列表
        tags = tags.split(',')
        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 修改数据
        result = table.update_one({"gid": gid}, {"$set": {"tags": tags}})
        res = {}
        return Response(res)


# 获取商品标签接口
class GetTags(View):
    def get(self, request):
        # 获取商品id
        gid = request.GET.get('gid', None)

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag
        # 查询数据
        res = table.find_one({'gid': str(gid)}, {'_id': 0, 'tags': 1})
        return HttpResponse(jsonb.dumps(res, ensure_ascii=False))


# redis存储标签接口
# class InsertTags_redis(APIView):
#     def get(self, request):
#         # 接收参数
#         gid = request.GET.get('gid', None)
#         tags = request.GET.get('tags', None)

#         r.set(gid, tags)
#         print(r.get(gid).decode('utf-8'))
#         return Response({'msg': '成功'})


# redis展示标签接口
# class GetTags_redis(APIView):
#     def get(self, request):
#         # 接收参数
#         gid = request.GET.get('gid', None)
#         tags = r.get(gid).decode('utf-8')
#         return Response({'tags': tags})


# 统计在线人数接口
class GetOnline(APIView):
    def get(self, request):
        # 获取客户ip
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META.get('HTTP_X_FORWARDED_FOR')
        else:
            ip = request.META.get('REMOTE_ADDR')
        # 存储用户ip
        r.sadd('online', ip)
        # 设置超时时间，超时时长单位：秒
        r.expire('online', 20)
        # 获取在线人数
        myset = r.smembers('online')
        # 返回数据
        return Response({'online': len(myset)})


# 防止用户恶意刷评论
def GetCount(request):
    # 获取客户ip
    if 'HTTP_X_FORWARDED_FOR' in request.META:
        ip = request.META.get('HTTP_X_FORWARDED_FOR')
    else:
        ip = request.META.get('REMOTE_ADDR')
    local_ip = r.smembers(str(ip))
    if local_ip:
        return False
    else:
        # 存储用户ip
        r.sadd(str(ip), '1')
        # 设置超时时间
        r.expire(str(ip), 60)
        # 获取保存的ip
        return True


# 反序列化入库（用户评论）
class InsertComment(APIView):
    def post(self, request):
        if GetCount(request) == True:
            # 初始化参数
            comment = CommentSer(data=request.data)
            # 数据校验
            if comment.is_valid():
                # 数据入库
                comment.create(comment.data)

            return Response({'msg': '评论成功'})
        else:
            return Response({'msg': '请勿频繁添加'})


# 评论列表
class CommentList(APIView):
    def get(self, request):
        # 接受参数
        gid = request.GET.get('gid')
        # 查询商品评论
        comments = Comment.objects.filter(gid=int(gid)).order_by('-id')
        if comments:
            # 设置新的数据列表
            clist = []
            # 遍历comments列表
            for comment in comments:
                # 查询每个uid的username
                user = User.objects.get(id=int(comment.uid))
                # 修改uid为username
                comment.uid = user.username
                # 将修改后的字典添加至新列表
                clist.append(comment)
            # 返回新列表
            comment_ser = CommentSer(clist, many=True).data
            return Response({'comment': comment_ser})
        else:
            return Response({'comment': [{'content': '暂无评论'}]})


# 对结果集美化方法
def dictfetchall(cursor):
    # 获取游标描述
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]


# 用户关注过的商品列表
class UserFlows(View):
    def get(self, request):
        uid = request.GET.get('uid', None)
        # 建立游标对象
        cursor = connection.cursor()
        # 执行sql语句
        cursor.execute(
            'select a.name,a.id from goods a left join userflow b on a.id = b.gid where b.uid = %s' % str(uid))

        # 获取结果
        # result = cursor.fetchall()
        result = dictfetchall(cursor)
        # 返回结果
        return HttpResponse(json.dumps(result, ensure_ascii=False, indent=4, default=str), content_type='application/json')


# 查询商品总关注数
class GoodsFlow(View):
    def get(self, request):
        gid = request.GET.get('gid')
        # 建立游标对象
        cursor = connection.cursor()
        # 执行sql语句
        cursor.execute(
            'select a.username from user a left join userflow b on a.id=b.uid where b.gid = %s' % str(gid))
        # 获取结果集
        result = dictfetchall(cursor)
        # 返回结果
        return HttpResponse(json.dumps(result, ensure_ascii=False), content_type='application/json')


# 关注（取消）商品接口
class GetFlow(APIView):
    def get(self, request):
        uid = request.GET.get('uid', None)
        gid = request.GET.get('gid', None)
        # 关注（1）或是取关（0）
        type = request.GET.get('type', 1)
        if(int(type)) == 1:
            # 关注
            user_flow = UserFlow(gid=int(gid), uid=int(uid))
            try:
                user_flow.save()
                msg = '关注成功'
                goods = Goods.objects.filter(id=int(gid)).first()
                goods.flow += 1
                goods.save()
            except Exception as e:
                return Response({'msg': '请勿重复关注'})
        elif int(type) == 0:
            # 取关
            userflow = UserFlow.objects.filter(
                uid=int(uid), gid=int(gid)).first()
            if userflow:
                userflow.delete()
                msg = '取消关注成功'
                goods = Goods.objects.filter(id=int(gid)).first()
                goods.flow -= 1
                goods.save()
        else:
            # 批量取关
            gids = request.GET.get('gids', None)
            # 强转
            id_list = eval(gids)
            # 查询用户关注的商品id
            user_flow_gids = UserFlow.objects.filter(uid=int(uid))
            glist = [u_f_gid.gid for u_f_gid in user_flow_gids]
            for gid in id_list:
                if gid in glist:
                    UserFlow.objects.filter(
                        gid=int(gid), uid=int(uid)).first().delete()
                else:
                    pass
            msg = '取消关注成功'

        return Response({'msg': msg})


# 搜索商品接口
class SearchGoods(APIView):
    def get(self, request):
        # 接收用户输入的内容
        inputname = request.GET.get('inputname')
        # 查找商品(模糊匹配)
        goodslist = Goods.objects.filter(
            Q(name__icontains=inputname) | Q(desc__icontains=inputname))
        if goodslist:
            goods_ser = GoodsSer(goodslist, many=True).data
            return Response({'code': 200, 'data': goods_ser})
        else:
            return Response({'code': 405, 'msg': '没有搜索到该商品'})


# 商品浏览次数接口
class ProductViewTimes(APIView):
    # 增加商品浏览次数
    def post(self, request):
        # 接收参数
        gid = request.data.get('gid')
        # 查找商品名称
        goods_name = Goods.objects.get(id=gid).name
        # 将商品名称及其浏览次数添加到redis有序集合
        r.zincrby('top', 1, goods_name)
        # 设置过期时间为一天
        r.expire('top', 3600 * 24)
        # 遍历有序集合
        # print(r.zrange('top', 0, -1, desc=True, withscores=True))
        return Response({'code': 200})

    # 查询商品排行榜
    def get(self, request):
        # 获取redis排行榜前五
        toplist = r.zrevrange('top', 0, 4)
        return Response({'data': toplist})



